home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / win / pascal / modialg.exe / MDITYPES.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-11-30  |  26.2 KB  |  659 lines

  1. {**********************************************************************
  2.  
  3.     MDI Program Support Objects        $Version$
  4.         $Author$            $Date$
  5.  
  6.         Copyright (c) 1991 Anthony M. Vitabile.
  7.         All rights reserved.
  8.  
  9.         Permission is hereby granted to all who desire to use this
  10.         source code in their programs provided the above copyright
  11.         is included in the program.
  12.  
  13.         Unit Description
  14.  
  15.         This unit implements three basic object types for use in MDI
  16.         programs under Windows.  These are:
  17.  
  18.         TMDIChild:  A normal MDI child window which supports the use of
  19.         a special menu whenever the window is active;
  20.  
  21.         TMDIDialog:  An MDI window which contains a modeless dialog box
  22.         as its only child.  The window adjusts itself so that it looks
  23.         like the non-client portion of a dialog box.
  24.  
  25.         TMDIFrame:  A frame window type descended from TMDIWindow that
  26.         supports locating and closing a particular child window when
  27.         that child window's handle is provided to it.  This can serve
  28.         as the basis for a method that closes the currently active
  29.         MDI child window.
  30.  
  31. **********************************************************************}
  32.  
  33. Unit MDITypes;
  34. Interface
  35.   Uses WinTypes, WObjects;
  36.  
  37.   type
  38.     PMDIChild  = ^TMDIChild;
  39.     PMDIDialog = ^TMDIDialog;
  40.     PMDIFrame  = ^TMDIFrame;
  41.  
  42.     TMDIChild  = object (TWindow)
  43.                    MenuPos:  integer;
  44.                    Menu   ,
  45.                    WndMenu:  HWnd;
  46.  
  47.                    constructor Init(AParent :  PWindowsObject;
  48.                                     ATitle  :  PChar;
  49.                                     AMenu   :  HMenu;
  50.                                     AMenuPos:  integer);
  51.                    constructor Load(var S:  TStream);
  52.                    procedure Store(var S:  TStream);
  53.                    procedure wmMDIActivate(var Msg:  TMessage);
  54.                      virtual wm_First + wm_MDIActivate;
  55.                  end;
  56.  
  57.     TMDIDialog = object (TMDIChild)
  58.                    SysMenu  :  HMenu;
  59.                    NCHeight :  integer;
  60.                    TheDialog:  PDlgWindow;
  61.  
  62.                    procedure ActivateDlg(var Msg:  TMessage);
  63.                    destructor Done;
  64.                      virtual;
  65.                    constructor Init(AParent :  PWindowsObject;
  66.                                     ATitle  :  PChar;
  67.                                     AMenu   :  HMenu;
  68.                                     AMenuPos:  integer);
  69.                    function InitDialog:  PDlgWindow;
  70.                      virtual;
  71.                    constructor Load(var S:  TStream);
  72.                    procedure Store(var S:  TStream);
  73.                    procedure SetChildFocus(var Msg:  TMessage);
  74.                    procedure SetupWindow;
  75.                      virtual;
  76.                    procedure wmActivate(var Msg:  TMessage);
  77.                      virtual wm_First + wm_Activate;
  78.                    procedure wmChildActivate(var Msg:  TMessage);
  79.                      virtual wm_First + wm_ChildActivate;
  80.                    procedure wmInitMenu(var Msg:  TMessage);
  81.                      virtual wm_First + wm_InitMenu;
  82.                    procedure wmGetText(var Msg:  TMessage);
  83.                      virtual wm_First + wm_GetText;
  84.                    procedure wmMDIActivate(var Msg:  TMessage);
  85.                      virtual wm_First + wm_MDIActivate;
  86.                    procedure wmSetFocus(var Msg:  TMessage);
  87.                      virtual wm_First + wm_SetFocus;
  88.                    procedure wmSize(var Msg:  TMessage);
  89.                      virtual wm_First + wm_Size;
  90.                    procedure wmSysCommand(var Msg:  TMessage);
  91.                      virtual wm_First + wm_SysCommand;
  92.                  end;
  93.  
  94.     TMDIFrame  = object (TMDIWindow)
  95.                    procedure CloseChild(AChild:  PWindowsObject);
  96.                      virtual;
  97.                    function GetChild(TheWnd:  HWnd):  PWindowsObject;
  98.                      virtual;
  99.                    procedure wmInitMenu(var Msg:  TMessage);
  100.                      virtual wm_First + wm_InitMenu;
  101.                    procedure wmInitMenuPopup(var Msg:  TMessage);
  102.                      virtual wm_First + wm_InitMenuPopup;
  103.                  end;
  104.  
  105. Implementation
  106.   Uses Strings, WinProcs;
  107.  
  108.   const
  109.     RMDIChild :  TStreamRec = (ObjType: 10000;
  110.                                VmtLink: Ofs(TypeOf(TMDIChild)^);
  111.                                Load:    @TMDIChild.Load;
  112.                                Store:   @TMDIChild.Store);
  113.  
  114.     RMDIDialog:  TStreamRec = (ObjType: 10001;
  115.                                VmtLink: Ofs(TypeOf(TMDIDialog)^);
  116.                                Load:    @TMDIDialog.Load;
  117.                                Store:   @TMDIDialog.Store);
  118.  
  119.     RMDIFrame :  TStreamRec = (ObjType: 10002;
  120.                                VmtLink: Ofs(TypeOf(TMDIFrame)^);
  121.                                Load:    @TMDIFrame.Load;
  122.                                Store:   @TMDIFrame.Store);
  123.  
  124. {**********************************************************************
  125.  
  126.     TMDIChild Methods
  127.  
  128.     Init Constructor.  Creates & initlializes an instance of
  129.         TMDIChild.  Most of the window's initialization is passed onto
  130.         TWindow, the ancestor object type of this type.  We save the
  131.         child's frame menu handle in the inherited Attr.Menu field, then
  132.         save the handle of the Window popup menu, whose position in the
  133.         menu is given by AMenuPos.
  134.  
  135. **********************************************************************}
  136.  
  137.   constructor TMDIChild.Init(AParent :  PWindowsObject;
  138.                              ATitle  :  PChar;
  139.                              AMenu   :  HMenu;
  140.                              AMenuPos:  integer);
  141.     begin    { TMDIChild.Init }
  142.       TWindow.Init(AParent, ATitle);
  143.       Menu    := AMenu;
  144.       MenuPos := AMenuPos;
  145.       if Menu = 0
  146.         then WndMenu := 0
  147.         else WndMenu := GetSubMenu(Menu, MenuPos)
  148.     end        { TMDIChild.Init };
  149.  
  150. {**********************************************************************
  151.  
  152.     Load Constructor.  Creates & initlializes an instance of
  153.         TMDIChild that has been read from a stream.
  154.  
  155. **********************************************************************}
  156.  
  157.   constructor TMDIChild.Load(var S:  TStream);
  158.     begin    { TMDIChild.Load }
  159.       TWindow.Load(S);
  160.       S.Read(Menu   , sizeof(Menu));
  161.       S.Read(MenuPos, sizeof(MenuPos));
  162.       WndMenu := 0
  163.     end        { TMDIChild.Load };
  164.  
  165. {**********************************************************************
  166.  
  167.     Store method.  Writes an instance of a TMDIChild onto the stream.
  168.  
  169. **********************************************************************}
  170.  
  171.   procedure TMDIChild.Store(var S:  TStream);
  172.     begin    { TMDIChild.Store }
  173.       TWindow.Store(S);
  174.       S.Write(Menu   , sizeof(Menu));
  175.       S.Write(MenuPos, sizeof(MenuPos))
  176.     end        { TMDIChild.Store };
  177.  
  178. {**********************************************************************
  179.  
  180.         wmMDIActivate message handler.  This method is executed whenever
  181.         the MDI child window receives a wm_MDIActivate message.  The
  182.         action taken is to reset the menu currently being used by the
  183.         current frame window to either the menu specified by the
  184.         Attr.Menu field of this TMDIChild instance if the window is
  185.         being activated (wParam <> 0), or to reset it to the default
  186.         menu for the frame as specified by the frame's Attr.Menu field.
  187.  
  188.         Note that in either case, if the handle of the new menu is 0,
  189.         then the current menu is not changed!
  190.  
  191. **********************************************************************}
  192.  
  193.   procedure TMDIChild.wmMDIActivate(var Msg:  TMessage);
  194.     var
  195.       NewMenu     ,
  196.       NewPos      :  HMenu;
  197.       MDIClient   :  PMDIClient;
  198.       MDIClientWnd:  HWnd;
  199.  
  200.     begin    { TMDIChild.wmMDIActivate }
  201.       MDIClient    := PMDIWindow(Parent)^.GetClient;
  202.       MDIClientWnd := MDIClient^.HWindow;
  203.       if Msg.WParam = 0
  204.         then
  205.           begin                    { Get frame window menu data  }
  206.             NewMenu := PMDIWindow(Parent)^.Attr.Menu;
  207.             NewPos  := MDIClient^.ClientAttr.hWindowMenu
  208.           end
  209.         else
  210.           begin                    { Get MDI child window menu data }
  211.             NewMenu := Menu;
  212.             NewPos  := WndMenu
  213.           end;                    { Now Set the menu up }
  214.       if NewMenu <> 0
  215.         then
  216.           begin
  217.             SendMessage(MDIClientWnd, wm_MDISetMenu, 0, MakeLong(NewMenu, NewPos));
  218.             DrawMenuBar(Parent^.HWindow)    { Redraw the menu bar }
  219.           end;
  220.       Msg.Result := 0                { Return 0 }
  221.     end        { TMDIChild.wmMDIActivate };
  222.  
  223. {**********************************************************************
  224.  
  225.     TMDIDialog methods
  226.  
  227.         Activate the child dialog box method.  This method is called
  228.         whenever the MDI dialog is activated or receives a message which
  229.         affects the keyboard handling.  If the window is not an icon,
  230.         then the current keyboard handler is set to the window's child
  231.         dialog box.  Otherwise, the keyboard handler is set to nil.
  232.  
  233. **********************************************************************}
  234.  
  235.   procedure TMDIDialog.ActivateDlg(var Msg:  TMessage);
  236.     begin    { TMDIDialog.ActivateDlg }
  237.       if IsIconic(HWindow)                { If the window isn't an icon right now }
  238.         then Application^.SetKBHandler(nil)        { Otherwise turn off the keyboard handler }
  239.         else Application^.SetKBHandler(TheDialog);    { Turn on the dialog's keyboard handler }
  240.       Msg.Result := 0
  241.     end        { TMDIDialog.ActivateDlg };
  242.  
  243. {**********************************************************************
  244.  
  245.     Destroys a TMDIDialog.  The routine first disposes of the
  246.         child dialog box, then destroys itself.
  247.  
  248. **********************************************************************}
  249.  
  250.   destructor TMDIDialog.Done;
  251.     begin    { TMDIDialog.Done }
  252.       dispose(TheDialog, Done);
  253.       Menu    := 0;
  254.       WndMenu := 0;
  255.       Sysmenu := 0;
  256.       TMDIChild.Done
  257.     end        { TMDIDialog.Done };
  258.  
  259. {**********************************************************************
  260.  
  261.     Init contructor.  This method creates a new TMDIDialog.  It
  262.         allows TMDIChild to do most of the initialization, and then it
  263.         initializes the handle of the window's system menu to 0.  It
  264.         then calls the virtual method InitDialog to actually create
  265.         an OWL TDlgWindow object.
  266.  
  267. **********************************************************************}
  268.  
  269.   constructor TMDIDialog.Init(AParent :  PWindowsObject;
  270.                               ATitle  :  PChar;
  271.                               AMenu   :  HMenu;
  272.                               AMenuPos:  integer);
  273.     begin    { TMDIDialog.Init }
  274.       TMDIChild.Init(AParent, ATitle, AMenu, AMenuPos);
  275.       SysMenu   := 0;
  276.       TheDialog := InitDialog
  277.     end        { TMDIDialog.Init };
  278.  
  279. {**********************************************************************
  280.  
  281.     InitDialog method.  This method creates a TDlgWindow, which
  282.         is to be the child of the TMDIDialog window.  This is an
  283.         abstract method which must be overridden by a descendant type.
  284.  
  285. **********************************************************************}
  286.  
  287.   function TMDIDialog.InitDialog:  PDlgWindow;
  288.     begin    { TMDIDialog.InitDialog }
  289.       abstract
  290.     end        { TMDIDialog.InitDialog };
  291.  
  292. {**********************************************************************
  293.  
  294.     Load Constructor.  Creates & initlializes an instance of
  295.         TMDIDialog that has been read from a stream.
  296.  
  297. **********************************************************************}
  298.  
  299.   constructor TMDIDialog.Load(var S:  TStream);
  300.     begin    { TMDIDialog.Load }
  301.       TMDIChild.Load(S);
  302.       GetChildPtr(S, TheDialog)
  303.     end        { TMDIChild.Load };
  304.  
  305. {**********************************************************************
  306.  
  307.     Store method.  Writes an instance of a TMDIDialog onto the stream.
  308.  
  309. **********************************************************************}
  310.  
  311.   procedure TMDIDialog.Store(var S:  TStream);
  312.     begin    { TMDIDialog.Store }
  313.       TMDIChild.Store(S);
  314.       PutChildPtr(S, TheDialog)
  315.     end        { TMDIDialog.Store };
  316.  
  317. {**********************************************************************
  318.  
  319.     SetChildFocus method.  This method is responsible for saving
  320.         and properly restoring the focus to the TDlgWindow's child
  321.         controls once the TMDIDialog gains or loses activation or
  322.         focus.  The method uses the TMDIDialog's FocusChildHandle
  323.         field, inherited from TWindow, to track the handle of the
  324.         dialog's child that has the focus at the time the window is
  325.         deactivated.
  326.  
  327. **********************************************************************}
  328.  
  329.   procedure TMDIDialog.SetChildFocus(var Msg:  TMessage);
  330.     var
  331.       CurrentFocus,
  332.       Dlg         :  HWnd;
  333.  
  334.     begin    { TMDIDialog.SetChildFocus }
  335.       Dlg := TheDialog^.HWindow;            { Make life easier for us }
  336.       if not IsIconic(HWindow)                { If the window isn't an icon right now }
  337.         then
  338.           if Msg.wParam <> 0                { If the window is being activated }
  339.             then                    { Set the focus to the correct child handle }
  340.               begin
  341.                 if FocusChildHandle = 0            { If we haven't got any focus yet }
  342.                   then SetFocus(TheDialog^.HWindow)    { Then set the focus to the dialog }
  343.                   else                    { Set the focus to the correct window }
  344.                     if IsWindow(FocusChildHandle)    { Make sure we have a valid handle here! }
  345.                       then SetFocus(FocusChildHandle)
  346.               end
  347.             else                    { Save the current focus }
  348.               begin
  349.                 CurrentFocus := GetFocus;        { Get the window that current has focus }
  350.                 if (CurrentFocus <> 0) and        { If there is one that has the focus }
  351.                     IsChild(Dlg, CurrentFocus)        { And it's a child of the dialog }
  352.                   then FocusChildHandle := CurrentFocus    { Then save the child's handle }
  353.               end;
  354.       Msg.Result := 0
  355.     end        { TMDIDialog.SetChildFocus };
  356.  
  357. {**********************************************************************
  358.  
  359.     SetupWindow.  Creates all window elements and then sets the
  360.         focus to the child TDlgWindow dialog box.  It then initializes
  361.         FocusChildHandle to the handle of the window that currently has
  362.         the focus.
  363.  
  364. **********************************************************************}
  365.  
  366.   procedure TMDIDialog.SetupWindow;
  367.     var
  368.       h   ,
  369.       w   :  integer;
  370.       Rect:  TRect;
  371.  
  372.     begin    { TMDIDialog.SetupWindow }
  373.       TMDIChild.SetupWindow;            { Do ancestor setup }
  374.       SetFocus(TheDialog^.HWindow);        { Set the focus to the dialog }
  375.       GetWindowRect(HWindow, Rect);        { Get the window's rectangle }
  376.       h := Rect.bottom - Rect.top;        { Compute the rectangle's height }
  377.       GetClientRect(HWindow, Rect);        { Now get the window's client rectangle }
  378.       NCHeight := h - Rect.bottom - Rect.top;    { The correct Non-Client height is the height difference }
  379.       GetClientRect(TheDialog^.HWindow, Rect);    { Finally, get the dialog box's client rectangle }
  380.       Attr.H := Rect.bottom - Rect.top + NCHeight;
  381.       Attr.W := Rect.right  - Rect.left
  382.     end        { TMDIDialog.SetupWindow };
  383.  
  384.  
  385. {**********************************************************************
  386.  
  387.     Track the window's activation state.  When this message is
  388.         received, the window must activate the child dialog and then
  389.         set the child focus.  This message is received when the parent
  390.         application is restored from an icon.  The top most MDI child
  391.         gets the message immediately following the restoration of
  392.         the Frame window.
  393.  
  394. **********************************************************************}
  395.  
  396.   procedure TMDIDialog.wmActivate(var Msg:  TMessage);
  397.     begin    { TMDIDialog.wmActivate }
  398.       ActivateDlg  (Msg);
  399.       SetChildFocus(Msg);
  400.       DefWndProc   (Msg)
  401.     end        { TMDIDialog.wmActivate };
  402.  
  403. {**********************************************************************
  404.  
  405.     We get this message because Windows is playing with the dialog
  406.         window.  This usually happens during processing of wm_Activate
  407.         and wm_MDIActivate.  We activate the child TDlgWindow dialog
  408.         box's keyboard handler after first passing it onto the default
  409.         message procedure for the window.
  410.  
  411.         NOTE THAT WE LEAVE THE FOCUS ALONE!
  412.  
  413. **********************************************************************}
  414.  
  415.   procedure TMDIDialog.wmChildActivate(var Msg:  TMessage);
  416.     begin    { TMDIDialog.wmChildActivate }
  417.       ActivateDlg(Msg);
  418.       DefWndProc (Msg)
  419.     end        { TMDIDialog.wmChildActivate };
  420.  
  421. {**********************************************************************
  422.  
  423.     This method adds code to the wm_GetText handling that stores
  424.         current dialog box child window control handle.  This is done
  425.         here to handle the case where the current dialog box has the
  426.         focus & control is switched away from the application without
  427.         minimizing it.
  428.  
  429.         It is *important* that this method call DefWndProc!!!!!!!!
  430.  
  431. **********************************************************************}
  432.  
  433.   procedure TMDIDialog.wmGetText(var Msg:  TMessage);
  434.     var
  435.       CurFocus:  HWnd;
  436.  
  437.     begin    { TMDIDialog.wmGetText }
  438.       CurFocus := GetFocus;                { Get the window that current has focus }
  439.       if (CurFocus <> 0) and                { If there is one that has the focus }
  440.           IsChild(TheDialog^.HWindow, CurFocus)        { And it's a child of the dialog }
  441.         then FocusChildHandle := CurFocus;        { Then save the child's handle }
  442.       DefWndProc(Msg)
  443.     end        { TMDIDialog.wmGetText };
  444.  
  445. {**********************************************************************
  446.  
  447.     This method handles saving the focus for the current dialog
  448.         child window when a menu item is selected.  This helps to ensure
  449.         that the focus goes to the right control at all times.
  450.  
  451.         The method also disables the Maximize and Size options on the
  452.         child window's system menu.  This allows the code to prevent
  453.         the window's size from being changed.
  454.  
  455. **********************************************************************}
  456.  
  457.   procedure TMDIDialog.wmInitMenu(var Msg:  TMessage);
  458.     var
  459.       CurFocus:  HWnd;
  460.  
  461.     begin    { TMDIDialog.wmInitMenu }
  462.       CurFocus := GetFocus;                { Get the window that current has focus }
  463.       if (CurFocus <> 0) and                { If there is one that has the focus }
  464.           IsChild(TheDialog^.HWindow, CurFocus)        { And it's a child of the dialog }
  465.         then FocusChildHandle := CurFocus;        { Then save the child's handle }
  466.       if SysMenu = 0
  467.         then SysMenu := GetSystemMenu(HWindow, FALSE);    { Get the window's system menu }
  468.       EnableMenuItem(SysMenu, sc_Maximize,        { Disable the maximize menu item }
  469.                      mf_Grayed or mf_ByCommand);
  470.       EnableMenuItem(SysMenu, sc_Size,            { Disable the sizing   menu item }
  471.                      mf_Grayed or mf_ByCommand);
  472.       DefWndProc(Msg)
  473.     end        { TMDIDialog.wmInitMenu };
  474.  
  475. {**********************************************************************
  476.  
  477.     This method handles the case of the TMDIDialog window being
  478.         activated or deactivated.  The message is handled by first
  479.         calling the TMDIChild method of the same name, so that the
  480.         menu can be reset.  We then activate the child dialog box's
  481.         keyboard handler and then set the focus to the correct child
  482.         control.
  483.  
  484. **********************************************************************}
  485.  
  486.   procedure TMDIDialog.wmMDIActivate(var Msg:  TMessage);
  487.     begin    { TMDIDialog.wm_MDIActivate }
  488.       TMDIChild.wmMDIActivate(Msg);        { Change the frame window's menu }
  489.       ActivateDlg  (Msg);            { Activate the dialog's keyboard handler }
  490.       SetChildFocus(Msg)            { Reset the focus to the correct control }
  491.     end        { TMDIDialog.wmMDIActivate };
  492.  
  493. {**********************************************************************
  494.  
  495.     When the TMDIDialog window is activated, it also gets the focus.
  496.         We have to activate the child dialog box's keyboard handler and
  497.         pass the focus to the correct dialog box child window.  No
  498.         other processing is necessary.
  499.  
  500. **********************************************************************}
  501.  
  502.   procedure TMDIDialog.wmSetFocus(var Msg:  TMessage);
  503.     begin    { TMDIDialog.wmSetFocus }
  504.       ActivateDlg  (Msg);
  505.       SetChildFocus(Msg);
  506.       Msg.Result := 0
  507.     end        { TMDIDialog.wmSetFocus };
  508.  
  509. {**********************************************************************
  510.  
  511.     This method prevents the TMDIDialog window from being any
  512.         larger or smaller than its child dialog box.  This helps keep
  513.         the appearance of the window consistent with that of the
  514.         dialog box it's impersonating on screen.
  515.  
  516.         If the window is not being displayed normally (wParam <>
  517.         SizeNormal), we just pass this message to the default window
  518.         procedure.  If we're displaying normally, we compute:
  519.  
  520.         The height of the non-client area;
  521.         The height & width of the dialog;
  522.         The height & width that the window needs to be to accomodate
  523.         all of the above (width of dialog, height of dialog + height
  524.         of the non-client area).
  525.  
  526. **********************************************************************}
  527.  
  528.   procedure TMDIDialog.wmSize(var Msg:  TMessage);
  529.     var
  530.       W, H      :  integer;
  531.       DialogRect:  TRect;
  532.  
  533.     begin    { TMDIDialog.wmSize }
  534.       if Msg.wParam = SizeNormal            { If we're doing a normal show }
  535.         then
  536.           begin
  537.             with Attr do
  538.               SetWindowPos(HWindow, 0, X, Y, W, H,    { Set the window's height without moving it }
  539.                          swp_NoZOrder or swp_NoMove);
  540.             MoveWindow(TheDialog^.HWindow, 0, 0, W,    { Correctly place the dialog in the window }
  541.                        H - NCHeight, TRUE);
  542.             UpdateWindow(HWindow)            { Redraw the window immediately }
  543.           end;
  544.       DefWndProc(Msg)
  545.     end        { TMDIDialog.wmSize };
  546.  
  547. {**********************************************************************
  548.  
  549.     This method ensures that the dialog box child control focus
  550.         is properly saved in the case where the MDI window is iconized
  551.         but has never received wm_MDIActivate with wParam = 0.
  552.  
  553. **********************************************************************}
  554.  
  555.   procedure TMDIDialog.wmSysCommand(var Msg:  TMessage);
  556.     var
  557.       CurFocus:  HWnd;
  558.       MenuItem:  Word;
  559.  
  560.     begin    { TMDIDialog.wmSysCommand }
  561.       CurFocus := GetFocus;                { Get the window that current has focus }
  562.       if (CurFocus <> 0) and                { If there is one that has the focus }
  563.           IsChild(TheDialog^.HWindow, CurFocus)        { And it's a child of the dialog }
  564.         then FocusChildHandle := CurFocus;        { Then save the child's handle }
  565.       MenuItem := (Msg.wParam and $FFF0);
  566.       if (MenuItem = sc_Maximize) or
  567.          (MenuItem = sc_Size)
  568.         then Msg.Result := 1
  569.         else DefWndProc(Msg)
  570.     end        { TMDIDialog.wmSysCommand };
  571.  
  572. {**********************************************************************
  573.  
  574.     TMDIFrame methods
  575.  
  576.         This method closes & destroys a child window.  AChild is a
  577.         pointer to an OWL object representing the child being closed.
  578.         The method first checks the pointer to make sure it's valid,
  579.         then it checks to see if the object's window handle is a child
  580.         of the MDI Client window.  If both of these conditions are
  581.         met, the window is destroyed.  Otherwise, the method just exits
  582.  
  583. **********************************************************************}
  584.  
  585.   procedure TMDIFrame.CloseChild(AChild:  PWindowsObject);
  586.     begin    { TMDIFrame.CloseChild }
  587.       if (AChild <> nil) and
  588.          IsChild(GetClient^.HWindow, AChild^.HWindow)
  589.         then
  590.           if AChild^.CanClose
  591.             then dispose(AChild, Done)
  592.     end        { TMDIFrame.CloseChild };
  593.  
  594. {**********************************************************************
  595.  
  596.     This method is used to find the pointer to the OWL object
  597.         which has the handle passed in TheWnd.
  598.  
  599. **********************************************************************}
  600.  
  601.   function TMDIFrame.GetChild(TheWnd:  HWnd):  PWindowsObject;
  602.  
  603.     function HandlesMatch(Window:  PWindowsObject):  boolean; far;
  604.       begin    { HandlesMatch }
  605.         HandlesMatch := Window^.HWindow = TheWnd
  606.       end    { HandlesMatch };
  607.  
  608.     begin    { TMDIFrame.GetChild }
  609.       GetChild := FirstThat(@HandlesMatch)
  610.     end        { TMDIFrame.GetChild };
  611.  
  612. {**********************************************************************
  613.  
  614.     This method passes the wm_InitMenu message on to the currently
  615.         active MDI child window.  This allows us to easily implement
  616.         child-window specific menu handling for MDI child windows,
  617.         especially edit windows.
  618.  
  619. **********************************************************************}
  620.  
  621.   procedure TMDIFrame.wmInitMenu(var Msg:  TMessage);
  622.     var
  623.       CurMDIHwnd:  HWnd;
  624.  
  625.     begin    { TMDIFrame.wmInitMenu }
  626.       CurMDIHwnd := LoWord(SendMessage(ClientWnd^.HWindow, wm_MDIGetActive, 0, 0));
  627.       if CurMDIHwnd <> 0
  628.         then SendMessage(CurMDIHwnd, wm_InitMenu, Msg.wParam, Msg.lParam);
  629.       Msg.result := 0
  630.     end        { TMDIFrame.wmInitMenu };
  631.  
  632. {**********************************************************************
  633.  
  634.     This method passes the wm_InitMenuPopup message on to the
  635.         currently active MDI child window.  This allows us to easily
  636.         implement child-window specific menu handling for MDI child
  637.         windows, especially edit windows.
  638.  
  639.         The MDI child should set Msg.result to 0 if it does not wish
  640.         the frame window to pass the message onto DefWndProc.
  641.  
  642. **********************************************************************}
  643.  
  644.   procedure TMDIFrame.wmInitMenuPopup(var Msg:  TMessage);
  645.     var
  646.       CurMDIHwnd:  HWnd;
  647.  
  648.     begin    { TMDIFrame.wmInitMenuPopup }
  649.       CurMDIHwnd := LoWord(SendMessage(ClientWnd^.HWindow, wm_MDIGetActive, 0, 0));
  650.       if CurMDIHwnd <> 0
  651.         then SendMessage(CurMDIHwnd, wm_InitMenuPopup, Msg.wParam, Msg.lParam);
  652.       Msg.result := 0
  653.     end        { TMDIFrame.wmInitMenuPopup };
  654.  
  655.   begin
  656.     RegisterType(RMDIChild);
  657.     RegisterType(RMDIDialog);
  658.     RegisterType(RMDIFrame);
  659.   end.